using System;
using System.Collections.Generic;
using System.Text;

using NUnit.Framework;

using System.Xml;

using OWED.Network.Messages;
using OWED.Network.Messages.General;
using OWED.Network.Messages.Reply;

using System.Threading;


/*
 * TODO:  Finish testing each request individually.
 * TODO:  Test multiple clients with one server
 */

namespace OWED.Network.Messages
{
    [TestFixture]
    public class TestProtocol
    {

 

        /*** Testing DeleteTag ***/
        /*  this stuff is basically trash
         * but it might make for a good template for testing other things.
         * So I'm leaving it!
        private XmlDocument deleteTagHandler(XmlDocument request)
        {
            Console.WriteLine("Server Got Request:");
            StringBuilder datFactory = new StringBuilder();
            XmlWriter wr = XmlWriter.Create(datFactory);
            request.Save(wr);
            Console.WriteLine(datFactory.ToString());
            Console.WriteLine("------------");

            XmlDocument reply = new OWED.Network.Messages.Reply.PassFail(false,
                "You're running test code, for deleteTag!").ToXml() as XmlDocument;
            Console.WriteLine("Replying...");

            DeleteTag message = DeleteTag.FromXml(request);
            Assert.IsTrue(message.User.Name.Equals("dave"));
            Assert.IsTrue(message.User.Password.Equals("abc"));
            Assert.IsTrue(message.DocName.Name.Equals("OLD_DOGS"));
            Assert.IsTrue(message.AbsolutePath.Path.ToString().
                                            Equals("/head/1/def/0"));

            return reply;
        }

        [Test]
        public void TestDeleteTag()
        {
            ConnectionServer s = new ConnectionServer(5027, deleteTagHandler);
            //server running...

            EventWaitHandle wait = new EventWaitHandle(false,
                                                     EventResetMode.AutoReset);

            Connection c = new Connection("localhost", 5027);

            XmlDocument doc = new DeleteTag(
                new User("dave", "abc"),
                new DocName("OLD_DOGS"),
                new AbsolutePath(
                        new Document.AbsolutePath("/head/1/def/0"))).ToXml()
                                                            as XmlDocument;

            OWEDReply response = delegate(XmlDocument document) {
                Console.WriteLine("Got Response:");
                StringBuilder datFactory = new StringBuilder();
                XmlWriter wr = XmlWriter.Create(datFactory);
                document.Save(wr);
                Console.WriteLine(datFactory.ToString());

                OWED.Network.Messages.Reply.PassFail p =
                    OWED.Network.Messages.Reply.PassFail.FromXml(document);
                Console.WriteLine("Passed:{0}", p.Pass);
                Console.WriteLine("Because:{0}", p.Reason);
                Console.WriteLine("--------");

                Assert.IsTrue(p.Pass == false);
                Assert.IsTrue(p.Reason.Equals(
                    "You're running test code, for deleteTag!"));

                wait.Set();
            };
            c.Send(doc, response);

            wait.WaitOne();
            s.Dispose();
        }*/
        /***Finished testing DeleteTag***/
        

        /*  multi-message test */
        
        public XmlDocument MultipleMessagesHandler(XmlDocument msg, 
													ref object connect,
													int number)
        {
            ApproveProposal proposal = ApproveProposal.FromXml(msg);
            int retid = proposal.ProposalID.number;

            PassFail p = new PassFail(false, 
                                        new Reason(12, retid.ToString()));

            //simulate processing:
            Thread.Sleep(new Random(retid * 1024 * 1024).Next(100, 1000));
            return p.ToXml() as XmlDocument;
        }

        [Test]
        public void TestMultipleSendMessages()
        {
            ConnectionServer s = new ConnectionServer(1120, 
                                            MultipleMessagesHandler);
            Connection c = new Connection("localhost", 1120);


            EventWaitHandle wait = new EventWaitHandle(false,
                                                     EventResetMode.AutoReset);
            int processed = 0;

            bool flaws = false;

            for (int i = 0; i < 32; ++i) {
                int Current = i;
                OWEDReply response = delegate(XmlDocument document) {

                    PassFail reply = PassFail.FromXml(document);
                    if (Current != int.Parse(reply.Reason.Value))
                        flaws = true;
                    Console.WriteLine("{0} -- {1}", Current, reply.Reason.Value);
                    ++processed;
                    if (processed >= 32)
                        wait.Set();
                };
                ApproveProposal change = new ApproveProposal(
                    new User("chris"),
                    new DocName("A_DOCUMENT"),
                    new ProposalID(i));
                c.Send(change.ToXml() as XmlDocument, response);
            }

            wait.WaitOne();
            s.Dispose();
            c.Dispose();

            Assert.IsTrue(flaws == false);
        }



        [Test]
        public void TestComments()
        {
            ServerHandler server = delegate(XmlDocument msg, ref object connect,
											int number) {
                GetComment request = GetComment.FromXml(msg);
                return new CommentReply(
                    new Comment(7, new User("Jeff"), 
                                new DiscussionID(request.DiscussionID.id),
                                new Date(2006, 11, 19, 11, 11, 11),
                                new Text("Dude, that's completely wrong!"))).ToXml();
            };

            ConnectionServer s = new ConnectionServer(1231, server);
            Connection c = new Connection("localhost", 1231);

            EventWaitHandle wait = new EventWaitHandle(false,
                                                     EventResetMode.AutoReset);
            CommentReply server_reply = null;

            OWEDReply response = delegate(XmlDocument document) {
                server_reply = CommentReply.FromXml(document);
                wait.Set();
            };

            c.Send(new GetComment(new User("Jeff"),
                                  new DiscussionID(7),
                                  new CommentRef(77)).ToXml(), response);
            wait.WaitOne();

            Console.WriteLine("Reply:{0}", server_reply.Comment.Text.Value);

            c.Dispose();
            s.Dispose();

            Assert.IsTrue(server_reply.Comment.id == 7);
            Assert.IsTrue(server_reply.Comment.Text.Value.
                Equals("Dude, that's completely wrong!"));
            Assert.IsTrue(server_reply.Comment.User.name.Equals("Jeff"));


        }
		[Test]
		public void TestMessageGet()
		{
            Create c = new Create(new User("chris"), new DocName("BOBS_DOC"));
			Create d = MessageGet.GetFromXml(c.ToXml()) as Create;
			Console.WriteLine(d);
			Assert.IsTrue(c.User.name.Equals(d.User.name));
			Assert.IsTrue(c.DocName.name.Equals(d.DocName.name));


			CreateDiscussion cd = new CreateDiscussion(
				new User("Jeff"), new DocName("BOREDOM"),
				new AbsolutePath("don't care"));
			CreateDiscussion copy = 
				MessageGet.GetFromXml(cd.ToXml()) as CreateDiscussion;
			Console.WriteLine(cd);
			Assert.IsTrue(cd.User.name.Equals(copy.User.name));
			Assert.IsTrue(cd.DocName.name.Equals(copy.DocName.name));
		}
		[Test]
		public void TestMultipleConnection()
		{
			ServerHandler server = delegate(XmlDocument msg, ref object connect,
											int number) {
				if (connect == null) {
					connect = 0;
					return new PassFail(false, new Reason(2, "No Reason")).ToXml();
				}  else
					return new PassFail(true, new Reason(2, "No Reason")).ToXml();
			};

			ConnectionServer s = new ConnectionServer(1031, server);
			Connection c = new Connection("localhost", 1031);

			EventWaitHandle wait = new EventWaitHandle(false,
													 EventResetMode.AutoReset);

			String error = null;

			OWEDReply response = delegate(XmlDocument document) {
				PassFail reply = MessageGet.GetFromXml(document) as PassFail;
				if (reply == null) {
					error = "Failed to correctly get reply type";
				} else {
					if (reply.pass) {
						error = null;
					} else
						error = "Multiple message broken";
				}
				wait.Set();
			};
			c.Send(new Login(new User("chris"), new Password("pass")).ToXml(), response);
            c.Send(new Login(new User("chris"), new Password("pass")).ToXml(), response);
			wait.WaitOne();
			wait.WaitOne();

			Assert.IsNull(error, error);

			c.Dispose();
			s.Dispose();
		}
		[Test]
		public void TestSynchronousClient()
		{
			ServerHandler server = delegate(XmlDocument msg, ref object connect,
											int number) {
				return new PassFail(true, new Reason(2, "No Reason")).ToXml();
			};

			ConnectionServer s = new ConnectionServer(1092, server);
			Connection c = new Connection("localhost", 1092);

            Login l = new Login(new User("chris"), new Password("pass"));

			PassFail reply = (PassFail)MessageGet.GetFromXml(c.Send(l.ToXml()));
			Assert.IsNotNull(reply);
			Assert.IsTrue(reply.pass);
			c.Dispose();
			s.Dispose();
		}
    }
}
